/**
 * The config parameter must consist of:<br />
 * <dl>
 * <dt>params</dt><dd>JSONObject containing 'key', 'locale', 'message', which represent the respective names of the parameters in which to encode those values.</dd>
 * <dt>locale</dt><dd>The locale valid for the messages on this page</dd>
 * <dt>saveURI</dt><dd>The URI to which to send a 'save' request.</dd>
 * <dt>confirmMessage</dt><dd>The message to show in the confirmation dialogue when auto-save data is present.</dd>
 * <dt>messages</dt><dd>A JSONObject in this form: {[key-value as String]:{"key":[key-value as String],"message":[message-value as String],"property":[property-value as String],"i8n":[i8n-value as String]},...}</dd>
 * </dl>
 * And may optionally contain:
 * <dl>
 * <dt>timeOut</dt><dd>The timeout interval with which tooltips remain visible. (NOT IMPLEMENTED YET)</dd>
 * </dl>
 * <br />
 * 
 * @param {JSONObject} config This is a JSONObject containing the important parameters required to instantiate this Object.
 * 
 * @author Martin 'Windgazer' Reurings.
 * @requires Prototype
 * @constructor
 */
function MessagesInterceptorTranslator( config ) {
	if (!config) {
		alert("ERROR 5282727478.28867283.001: No config supplied!");
		return null;
	}

	//Set config values to internal values
	this.saveURI = config.saveURI;
	this.params = config.params;
	this.locale = config.locale;
	var msg = this.msg = config.confirmMessage;
	var auth = this.auth = config.authMessage;
	var comm = this.comm = config.commMessage;
	var message = this.messages = config.messages;

	TranslatorHotKeyConfig.add(this);
}

MessagesInterceptorTranslator.prototype = {
	nonVisElementsRE:/title|option|script|link/i,
	/**
	 * May not always return an element, as not all keys are actually tied to an element...
	 * Always return the first one found, in case more than 1 exists...
	 */
	getElementByKey:function(key) {
		var elems = $$('[translate="messagekey:' + key + '"]');
		var elem = null;
		for (var i = 0; i < elems.length && elem==null; i++) {
			elem = elems[i];
			if (this.nonVisElementsRE.test(elem.nodeName)) elem = null;
		}
		return elem;
	},
	getElementKey:function(element) {
		var key = element.getAttribute("translate");
		if (key && key.length > 11) {
			key = key.substr(11);
			return key;
		}
		return null;
	},
	createToolTip:function(target, editor) {
		var element = target.translationElement;
		if (target.translatorTooltipActive) {
			window.clearTimeout(element.timer);
		} else {
			var msg = this.messages[this.getElementKey(element)];
			var tooltip = document.createElement("div");
			tooltip.className = "translatorTooltip";
	
			var title = document.createElement("h4");
			title.appendChild(document.createTextNode(msg.key));
			var dl = document.createElement("dl");

			var dt = document.createElement("dt");
			var dd = document.createElement("dd");
			dt.appendChild(document.createTextNode("i8n"))
			dd.appendChild(document.createTextNode(msg.i8n));
			dl.appendChild(dt);dl.appendChild(dd);

			dt = document.createElement("dt");
			dd = document.createElement("dd");
			dt.appendChild(document.createTextNode("live"))
			dd.appendChild(document.createTextNode(msg.live));
			dl.appendChild(dt);dl.appendChild(dd);

			dt = document.createElement("dt");
			dd = document.createElement("dd");
			dt.appendChild(document.createTextNode("property"))
			dd.appendChild(document.createTextNode(msg.property));
			dl.appendChild(dt);dl.appendChild(dd);

			tooltip.appendChild(title);
			tooltip.appendChild(dl);
	
			$$('body')[0].appendChild(tooltip);
			
			var offsetY = target.cumulativeOffset().top < tooltip.offsetHeight?target.offsetHeight:-tooltip.offsetHeight; //If too close to the top of the page, put it underneath...
			var offsetX = (target.cumulativeOffset().left + tooltip.offsetWidth) > $$('body')[0].offsetWidth?target.offsetWidth - tooltip.offsetWidth:0; //If too close to the right of the page, move it left...
	
			Element.clonePosition(tooltip, target, {setWidth:false,setHeight:false,offsetTop:offsetY,offsetLeft:offsetX});
			Element.extend(tooltip);
			target.translatorTooltipActive = tooltip;
		}
		
		var self = this;
		if (!editor)
			target.observe("mouseout", function(e) {
				self.mouseOutHandler(e, target);
			});
	},
	createEditor:function(element) {
		var key = this.getElementKey(element);
		var msg = this.messages[key];
		var editor = document.createElement("form");
		editor.className = "translationEditorForm";
		editor.action="#" + msg.key;
		var input = document.createElement("input");
		input.className = "translatorEditor";
		input.value = msg.property;
		editor.appendChild(input);
		var submit = document.createElement("input");
		submit.type="submit";
		submit.value="Save";
		submit.className="submit";
		editor.appendChild(submit);
		var reset = document.createElement("button");
		reset.appendChild(document.createTextNode("Revert"));
		reset.title="Reset this field to the 'live' value.";
		editor.appendChild(reset);
		Element.clonePosition(editor, element, {setWidth:false,setHeight:false});
		Element.clonePosition(input, element);
		$$('body')[0].appendChild(editor);
		input.select();
		input.focus();
		var self = this;
		editor.observe("submit", function(e) {
			self.saveEditorMessage(element, key, editor);
			e.stop();
			return false;
		});
		input.observe("keydown", function(e) {
			if (e.keyCode == Event.KEY_ESC) {
				self.removeEditor(editor);
			}
		});
		reset.observe("click", function(e) {
			input.value=msg.live;
			self.saveEditorMessage(element, key, editor);
			e.stop();
			return false;
		});
	},
	removeEditor:function(editor) {
		$$('body')[0].removeChild(editor);
	},
	saveEditorMessage:function(element, key, editor) {
		editor.firstChild.disabled = true;
		
		var self = this;
		//Set data for the post
		var body = this.params.key + "=" + escape(key);
		body += "&" + this.params.locale + "=" + escape(this.locale);
		body += "&" + this.params.message + "=" + escape(editor.firstChild.value);

		//Save the new message
		var request = new Ajax.Request(this.saveURI, {
			postBody:body,
			onSuccess:function(transport) {
				var results = transport.responseJSON;
				self.removeEditor(editor);
				self.updateElement(element, results);
			}
		});
	},
	updateElement:function(element, results) {
		var oldMsg = this.messages[results.key];
		oldMsg.message = results.message;
		oldMsg.live = results.live;
		
		this.messages[results.key] = oldMsg;
		element.removeChild(element.firstChild);
		element.appendChild(document.createTextNode(results.live));
	},
	mouseOverHandler:function(e) {
		var target = e.target||e.srcElement;
		if (target && target.translationElement && this.getElementKey(target.translationElement)) {
			this.createToolTip(target);
			return false;
		} return true;
	},
	mouseOutHandler:function(e, target) {
		target.timer = window.setTimeout(function(){
			target.translatorTooltipActive.fade({ afterFinish:function() {
				$$('body')[0].removeChild(target.translatorTooltipActive);
				target.translatorTooltipActive = false;
			}});
			window.clearTimeout(target.timer);
		}, 1000);
	},
	mouseClickHandler:function(e) {
		var target = e.target||e.srcElement;
		if (target && target.translationElement && this.getElementKey(target.translationElement)) {
			var self = this;
			window.setTimeout(function() {
				window.clearTimeout(target.timer);//TODO get this cancelation of the timer to function!
			}, 10);
			this.createEditor(target.translationElement);
			e.stop();
			return false;
		} return true;
	},
	enableTranslater:function() {
		var self = this;
		var body = $$('body')[0];
		var nonVisEditor = document.getElementById("msgInterceptNonVisEditor");
		if (nonVisEditor == null) {
			nonVisEditor = document.createElement("ul");
			nonVisEditor.id = "msgInterceptNonVisEditor";
			body.appendChild(nonVisEditor);
		}

		for (key in this.messages) {
			var element = this.getElementByKey(key);
			if (element != null && element.childNodes.length == 1) {
				var span = document.createElement("span");
				span.className = "translator_hint";
				span.appendChild(document.createTextNode("Edit"));
				body.appendChild(span);

				var offsetX = element.offsetWidth - span.offsetWidth;
				Element.clonePosition(span, element, {setWidth:false,setHeight:false,offsetLeft:offsetX});

				span.observe("mouseover", function(e) {
					return self.mouseOverHandler(e);
				});
				
				span.translationElement = element;
			} else {
				//add key to non-visible editor
				var msg = this.messages[key];

				var li = document.createElement("li");
				li.className = "translator_field";

				var lbl = document.createElement("label");
				lbl.innerHTML = key + ": ";
				li.appendChild(lbl);

				var span = document.createElement("span");
				span.innerHTML = msg.property;
				span.setAttribute("translate", 'messagekey:' + key );
				li.appendChild(span);

				var button = document.createElement("button");
				button.innerHTML = "Edit";
				button.translationElement = span;
				li.appendChild(button);
				
				nonVisEditor.appendChild(li);
			}
		}

		body.observe("click", function(e){
			return self.mouseClickHandler(e);
		});
		
	},
	disableTranslator:function() {

		for (key in this.messages) {
			var element = this.getElementByKey(key);
			if (element != null) {
				element.stopObserving("mouseover");
			}
		}

		var body = $$('body')[0]; 
		body.stopObserving("click");

		body.removeChild(document.getElementById("msgInterceptNonVisEditor"));

		$$(".translator_hint").each(function(element) {
			element.parentNode.removeChild(element);
		});
		
	}
}

var TranslatorHotKeyConfig = {
	enabled:false,
	translators:new Array(),
	start:function() {
		if (!this.enabled) {
			this.enabled = true;
			new HotKey('t',function(event){
				var body = $$('body')[0];
				var newCN = body.className.replace(/ ?\btranslator_ENABLED\b/g,"");
				if (body.className!=newCN) {
					TranslatorHotKeyConfig.disableTranslators();
					body.className = newCN;
				} else {
					TranslatorHotKeyConfig.enableTranslaters();
					body.className += " translator_ENABLED";
				}
			},{  
				altKey: true
			});
		}
	},
	disableTranslators:function() {
		for (var i = 0; i < this.translators.length; this.translators[i++].disableTranslator());
	},
	enableTranslaters:function() {
		for (var i = 0; i < this.translators.length; this.translators[i++].enableTranslater());
	},
	add:function(translator) {
		this.translators[this.translators.length] = translator;
	}
}


/**
 * A helper function, because in T5 this is the easiest way to add an init method.
 * If I use my own init method I try to instantiate before Prototype is finished
 * initializing, let's see if this solves that problem...
 */
function createNewMessagesInterceptorTranslator(config) {
	mit = new MessagesInterceptorTranslator(config);
	TranslatorHotKeyConfig.start();
	return mit;
}
//Checking for existance and then adding it to Tapestry's structure, trying to minimize the dependencies for this code...
if (Tapestry && Tapestry.Initializer) Tapestry.Initializer["createNewMessagesInterceptorTranslator"] = createNewMessagesInterceptorTranslator;


/**
 * This only enables the hotkeys, because we're trying to reuse as much code as
 * possible, this code will help show/hide the ExternalSource editor...
 */
function enableTranslatorHotkey(config) {
	TranslatorHotKeyConfig.start();
}
//Checking for existance and then adding it to Tapestry's structure, trying to minimize the dependencies for this code...
if (Tapestry && Tapestry.Initializer) Tapestry.Initializer["enableTranslatorHotkey"] = enableTranslatorHotkey;

